/**
 *
 *  You can modify and use this source freely
 *  only for the development of application related Live2D.
 *
 *  (c) Live2D Inc. All rights reserved.
 */
//============================================================
//============================================================
//  class L2DBaseModel         
//============================================================
//============================================================
function L2DBaseModel() {
    this.live2DModel = null; // ALive2DModel
    this.modelMatrix = null; // L2DModelMatrix
    this.eyeBlink = null; // L2DEyeBlink
    this.physics = null; // L2DPhysics
    this.pose = null; // L2DPose
    this.debugMode = false;
    this.initialized = false;
    this.updating = false;
    this.alpha = 1;
    this.accAlpha = 0;
    this.lipSync = false;
    this.lipSyncValue = 0;
    this.accelX = 0;
    this.accelY = 0;
    this.accelZ = 0;
    this.dragX = 0;
    this.dragY = 0;
    this.startTimeMSec = null;
    this.mainMotionManager = new L2DMotionManager(); //L2DMotionManager
    this.expressionManager = new L2DMotionManager(); //L2DMotionManager
    this.motions = {};
    this.expressions = {};
    this.lips = []; // added by ludy
    this.lip_index = 0; // added by ludy

    this.isTexLoaded = false;
}

var texCounter = 0;

//============================================================
//    L2DBaseModel # getModelMatrix()
//============================================================
L2DBaseModel.prototype.getModelMatrix = function() {
return this.modelMatrix;
}

//============================================================
//    L2DBaseModel # setAlpha()
//============================================================
L2DBaseModel.prototype.setAlpha = function(a /*float*/ ) {
if (a > 0.999)
    a = 1;
if (a < 0.001)
    a = 0;
this.alpha = a;
}

//============================================================
//    L2DBaseModel # getAlpha()
//============================================================
L2DBaseModel.prototype.getAlpha = function() {
return this.alpha;
}

//============================================================
//    L2DBaseModel # isInitialized()
//============================================================
L2DBaseModel.prototype.isInitialized = function() {
return this.initialized;
}

//============================================================
//    L2DBaseModel # setInitialized()
//============================================================
L2DBaseModel.prototype.setInitialized = function(v /*boolean*/ ) {
this.initialized = v;
}

//============================================================
//    L2DBaseModel # isUpdating()
//============================================================
L2DBaseModel.prototype.isUpdating = function() {
return this.updating;
}

//============================================================
//    L2DBaseModel # setUpdating()
//============================================================
L2DBaseModel.prototype.setUpdating = function(v /*boolean*/ ) {
this.updating = v;
}

//============================================================
//    L2DBaseModel # getLive2DModel()
//============================================================
L2DBaseModel.prototype.getLive2DModel = function() {
return this.live2DModel;
}

//============================================================
//    L2DBaseModel # setLipSync()
//============================================================
L2DBaseModel.prototype.setLipSync = function(v /*boolean*/ ) {
this.lipSync = v;
}

//============================================================
//    L2DBaseModel # setLipSyncValue()
//============================================================
L2DBaseModel.prototype.setLipSyncValue = function(v /*float*/ ) {
this.lipSyncValue = v;
}

//============================================================
//    L2DBaseModel # setAccel()
//============================================================
L2DBaseModel.prototype.setAccel = function(x /*float*/ , y /*float*/ , z /*float*/ ) {
this.accelX = x;
this.accelY = y;
this.accelZ = z;
}

//============================================================
//    L2DBaseModel # setDrag()
//============================================================
L2DBaseModel.prototype.setDrag = function(x /*float*/ , y /*float*/ ) {
this.dragX = x;
this.dragY = y;
}

//============================================================
//    L2DBaseModel # getMainMotionManager()
//============================================================
L2DBaseModel.prototype.getMainMotionManager = function() {
return this.mainMotionManager;
}

//============================================================
//    L2DBaseModel # getExpressionManager()
//============================================================
L2DBaseModel.prototype.getExpressionManager = function() {
return this.expressionManager;
}

//============================================================
//    L2DBaseModel # loadModelData()
//============================================================
L2DBaseModel.prototype.loadModelData = function(path /*String*/ , callback) {
/*
if( this.live2DModel != null ) {
    this.live2DModel.deleteTextures();
}
*/
var pm = Live2DFramework.getPlatformManager(); //IPlatformManager
if (this.debugMode) pm.log('Load model : ' + path);

var thisRef = this;
pm.loadLive2DModel(path, function(l2dModel) {
    thisRef.live2DModel = l2dModel;
    thisRef.live2DModel.saveParam();

    var _err = Live2D.getError();

    if (_err != 0) {
        console.error('Error : Failed to loadModelData().');
        return;
    }

    thisRef.modelMatrix = new L2DModelMatrix(
        thisRef.live2DModel.getCanvasWidth(),
        thisRef.live2DModel.getCanvasHeight()); //L2DModelMatrix
    thisRef.modelMatrix.setWidth(2);
    thisRef.modelMatrix.setCenterPosition(0, 0);

    callback(thisRef.live2DModel);
});
}


//============================================================
//    L2DBaseModel # loadTexture()
//============================================================
L2DBaseModel.prototype.loadTexture = function(no /*int*/ , path /*String*/ , callback) {
texCounter++;

var pm = Live2DFramework.getPlatformManager(); //IPlatformManager

if (this.debugMode) pm.log('Load Texture : ' + path);

var thisRef = this;
pm.loadTexture(this.live2DModel, no, path, function() {
    texCounter--;
    if (texCounter == 0)
        thisRef.isTexLoaded = true;
    if (typeof callback == 'function') callback();
});

}

//============================================================
//    L2DBaseModel # loadMotion()
//============================================================
L2DBaseModel.prototype.loadMotion = function(name /*String*/ , path /*String*/ , callback) {
var pm = Live2DFramework.getPlatformManager(); //IPlatformManager

if (this.debugMode) pm.log('Load Motion : ' + path);

var motion = null; //Live2DMotion

var thisRef = this;
pm.loadBytes(path, function(buf) {
    motion = Live2DMotion.loadMotion(buf);
    if (name != null) {
        thisRef.motions[name] = motion;
    }
    callback(motion);
});

}

//============================================================
//    L2DBaseModel # loadExpression()
//============================================================
L2DBaseModel.prototype.loadExpression = function(name /*String*/ , path /*String*/ , callback) {
var pm = Live2DFramework.getPlatformManager(); //IPlatformManager

if (this.debugMode) pm.log('Load Expression : ' + path);

var thisRef = this;
pm.loadBytes(path, function(buf) {
    if (name != null) {
        thisRef.expressions[name] = L2DExpressionMotion.loadJson(buf);
    }
    if (typeof callback == 'function') callback(L2DExpressionMotion.loadJson(buf));
});
}

//============================================================
//    L2DBaseModel # loadPose()
//============================================================
L2DBaseModel.prototype.loadPose = function(path /*String*/ , callback) {
var pm = Live2DFramework.getPlatformManager(); //IPlatformManager
if (this.debugMode) pm.log('Load Pose : ' + path);
var thisRef = this;
try {
    pm.loadBytes(path, function(buf) {
        thisRef.pose = L2DPose.load(buf);
        if (typeof callback == 'function') callback();
    });
} catch ( e ) {
    console.warn(e);
}
}

//============================================================
//    L2DBaseModel # loadPhysics()
//============================================================
L2DBaseModel.prototype.loadPhysics = function(path /*String*/ ) {
var pm = Live2DFramework.getPlatformManager(); //IPlatformManager
if (this.debugMode) pm.log('Load Physics : ' + path);
var thisRef = this;
try {
    pm.loadBytes(path, function(buf) {
        thisRef.physics = L2DPhysics.load(buf);
    });
} catch ( e ) {
    console.warn(e);
}
}

//============================================================
//    L2DBaseModel # hitTestSimple()
//============================================================
L2DBaseModel.prototype.hitTestSimple = function(drawID, testX, testY) {
var drawIndex = this.live2DModel.getDrawDataIndex(drawID);

if (drawIndex < 0) return false;

var points = this.live2DModel.getTransformedPoints(drawIndex);
var left = this.live2DModel.getCanvasWidth();
var right = 0;
var top = this.live2DModel.getCanvasHeight();
var bottom = 0;

for (var j = 0; j < points.length; j = j + 2) {
    var x = points[j];
    var y = points[j + 1];

    if (x < left)
        left = x;
    if (x > right)
        right = x;
    if (y < top)
        top = y;
    if (y > bottom)
        bottom = y;
}
var tx = this.modelMatrix.invertTransformX(testX);
var ty = this.modelMatrix.invertTransformY(testY);

return (left <= tx && tx <= right && top <= ty && ty <= bottom);
}

/**
 *
 *  You can modify and use this source freely
 *  only for the development of application related Live2D.
 *
 *  (c) Live2D Inc. All rights reserved.
 */

//============================================================
//============================================================
//  class L2DExpressionMotion  extends     AMotion
//============================================================
//============================================================
function L2DExpressionMotion() {
    AMotion.prototype.constructor.call(this);
    this.paramList = new Array(); //ArrayList<L2DExpressionParam>
}

L2DExpressionMotion.prototype = new AMotion(); // L2DExpressionMotion extends AMotion

//============================================================
L2DExpressionMotion.EXPRESSION_DEFAULT = 'DEFAULT';
L2DExpressionMotion.TYPE_SET = 0;
L2DExpressionMotion.TYPE_ADD = 1;
L2DExpressionMotion.TYPE_MULT = 2;

//============================================================
//    static L2DExpressionMotion.loadJson()
//============================================================
L2DExpressionMotion.loadJson = function(buf) {
var ret = new L2DExpressionMotion();

var pm = Live2DFramework.getPlatformManager();
var json = pm.jsonParseFromBytes(buf);

ret.setFadeIn(parseInt(json.fade_in) > 0 ? parseInt(json.fade_in) : 1000);
ret.setFadeOut(parseInt(json.fade_out) > 0 ? parseInt(json.fade_out) : 1000);

if (json.params == null) {
    return ret;
}

var params = json.params;
var paramNum = params.length;
ret.paramList = []; //ArrayList<L2DExpressionParam>
for (var i = 0; i < paramNum; i++) {
    var param = params[i];
    var paramID = param.id.toString();
    var value = parseFloat(param.val);
    var calcTypeInt = L2DExpressionMotion.TYPE_ADD;
    var calc = param.calc != null ? param.calc.toString() : 'add';
    if (calc === 'add') {
        calcTypeInt = L2DExpressionMotion.TYPE_ADD;
    } else if (calc === 'mult') {
        calcTypeInt = L2DExpressionMotion.TYPE_MULT;
    } else if (calc === 'set') {
        calcTypeInt = L2DExpressionMotion.TYPE_SET;
    } else {
        calcTypeInt = L2DExpressionMotion.TYPE_ADD;
    }
    if (calcTypeInt == L2DExpressionMotion.TYPE_ADD) {
        var defaultValue = param.def == null ? 0 : parseFloat(param.def);
        value = value - defaultValue;
    } else if (calcTypeInt == L2DExpressionMotion.TYPE_MULT) {
        var defaultValue = param.def == null ? 1 : parseFloat(param.def);
        if (defaultValue == 0)
            defaultValue = 1;
        value = value / defaultValue;
    }

    var item = new L2DExpressionParam();
    item.id = paramID;
    item.type = calcTypeInt;
    item.value = value;

    ret.paramList.push(item);
}

return ret;
}


//============================================================
//    L2DExpressionMotion # updateParamExe()
//============================================================
L2DExpressionMotion.prototype.updateParamExe = function(model /*ALive2DModel*/ , timeMSec /*long*/ , weight /*float*/ , motionQueueEnt /*MotionQueueEnt*/ ) {
for (var i = this.paramList.length - 1; i >= 0; --i) {
    var param = this.paramList[i]; //L2DExpressionParam
    // if (!param || !param.type) continue;
    if (param.type == L2DExpressionMotion.TYPE_ADD) {
        model.addToParamFloat(param.id, param.value, weight);
    } else if (param.type == L2DExpressionMotion.TYPE_MULT) {
        model.multParamFloat(param.id, param.value, weight);
    } else if (param.type == L2DExpressionMotion.TYPE_SET) {
        model.setParamFloat(param.id, param.value, weight);
    }
}
}

//============================================================
//============================================================
//  class L2DExpressionParam   
//============================================================
//============================================================
function L2DExpressionParam() {
    this.id = '';
    this.type = -1;
    this.value = null;
}

/**
 *
 *  You can modify and use this source freely
 *  only for the development of application related Live2D.
 *
 *  (c) Live2D Inc. All rights reserved.
 */

//============================================================
//============================================================
//  class L2DEyeBlink          
//============================================================
//============================================================
function L2DEyeBlink() {
    this.nextBlinkTime = null /* TODO NOT INIT */ ; // 
    this.stateStartTime = null /* TODO NOT INIT */ ; // 
    this.blinkIntervalMsec = null /* TODO NOT INIT */ ; // 
    this.eyeState = EYE_STATE.STATE_FIRST;
    this.blinkIntervalMsec = 4000;
    this.closingMotionMsec = 100;
    this.closedMotionMsec = 50;
    this.openingMotionMsec = 150;
    this.closeIfZero = true;
    this.eyeID_L = 'PARAM_EYE_L_OPEN';
    this.eyeID_R = 'PARAM_EYE_R_OPEN';
}

//============================================================
//    L2DEyeBlink # calcNextBlink()
//============================================================
L2DEyeBlink.prototype.calcNextBlink = function() {
var time /*long*/ = UtSystem.getUserTimeMSec();
var r /*Number*/ = Math.random();
return /*(long)*/ (time + r * (2 * this.blinkIntervalMsec - 1));
}

//============================================================
//    L2DEyeBlink # setInterval()
//============================================================
L2DEyeBlink.prototype.setInterval = function(blinkIntervalMsec /*int*/ ) {
this.blinkIntervalMsec = blinkIntervalMsec;
}

//============================================================
//    L2DEyeBlink # setEyeMotion()
//============================================================
L2DEyeBlink.prototype.setEyeMotion = function(closingMotionMsec /*int*/ , closedMotionMsec /*int*/ , openingMotionMsec /*int*/ ) {
this.closingMotionMsec = closingMotionMsec;
this.closedMotionMsec = closedMotionMsec;
this.openingMotionMsec = openingMotionMsec;
}

//============================================================
//    L2DEyeBlink # updateParam()
//============================================================
L2DEyeBlink.prototype.updateParam = function(model /*ALive2DModel*/ ) {
var time /*:long*/ = UtSystem.getUserTimeMSec();
var eyeParamValue /*:Number*/ ;
var t /*:Number*/ = 0;
switch (this.eyeState) {
case EYE_STATE.STATE_CLOSING:
    t = (time - this.stateStartTime) / this.closingMotionMsec;
    if (t >= 1) {
        t = 1;
        this.eyeState = EYE_STATE.STATE_CLOSED;
        this.stateStartTime = time;
    }
    eyeParamValue = 1 - t;
    break;
case EYE_STATE.STATE_CLOSED:
    t = (time - this.stateStartTime) / this.closedMotionMsec;
    if (t >= 1) {
        this.eyeState = EYE_STATE.STATE_OPENING;
        this.stateStartTime = time;
    }
    eyeParamValue = 0;
    break;
case EYE_STATE.STATE_OPENING:
    t = (time - this.stateStartTime) / this.openingMotionMsec;
    if (t >= 1) {
        t = 1;
        this.eyeState = EYE_STATE.STATE_INTERVAL;
        this.nextBlinkTime = this.calcNextBlink();
    }
    eyeParamValue = t;
    break;
case EYE_STATE.STATE_INTERVAL:
    if (this.nextBlinkTime < time) {
        this.eyeState = EYE_STATE.STATE_CLOSING;
        this.stateStartTime = time;
    }
    eyeParamValue = 1;
    break;
case EYE_STATE.STATE_FIRST:
default:
    this.eyeState = EYE_STATE.STATE_INTERVAL;
    this.nextBlinkTime = this.calcNextBlink();
    eyeParamValue = 1;
    break;
}
if (!this.closeIfZero)
    eyeParamValue = -eyeParamValue;
model.setParamFloat(this.eyeID_L, eyeParamValue);
model.setParamFloat(this.eyeID_R, eyeParamValue);
}

//== enum EYE_STATE ==
var EYE_STATE = function() {};

EYE_STATE.STATE_FIRST = 'STATE_FIRST'
EYE_STATE.STATE_INTERVAL = 'STATE_INTERVAL'
EYE_STATE.STATE_CLOSING = 'STATE_CLOSING'
EYE_STATE.STATE_CLOSED = 'STATE_CLOSED'
EYE_STATE.STATE_OPENING = 'STATE_OPENING'
/**
 *
 *  You can modify and use this source freely
 *  only for the development of application related Live2D.
 *
 *  (c) Live2D Inc. All rights reserved.
 */

//============================================================
//============================================================
//  class L2DMatrix44          
//============================================================
//============================================================
function L2DMatrix44() {
    this.tr = new Float32Array(16); // 
    this.identity();
}

//============================================================
//    static L2DMatrix44.mul()
//============================================================
L2DMatrix44.mul = function(a /*float[]*/ , b /*float[]*/ , dst /*float[]*/ ) {
var c = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
var n = 4;
var i,
    j,
    k;
for (i = 0; i < n; i++) {
    for (j = 0; j < n; j++) {
        for (k = 0; k < n; k++) {
            c[i + j * 4] += a[i + k * 4] * b[k + j * 4];
        }
    }
}
for (i = 0; i < 16; i++) {
    dst[i] = c[i];
}
}

//============================================================
//    L2DMatrix44 # identity()
//============================================================
L2DMatrix44.prototype.identity = function() {
for (var i /*:int*/ = 0; i < 16; i++)
    this.tr[i] = ((i % 5) == 0) ? 1 : 0;
}

//============================================================
//    L2DMatrix44 # getArray()
//============================================================
L2DMatrix44.prototype.getArray = function() {
return this.tr;
}

//============================================================
//    L2DMatrix44 # getCopyMatrix()
//============================================================
L2DMatrix44.prototype.getCopyMatrix = function() {
return new Float32Array(this.tr); // this.tr.clone();
}

//============================================================
//    L2DMatrix44 # setMatrix()
//============================================================
L2DMatrix44.prototype.setMatrix = function(tr /*float[]*/ ) {
if (this.tr == null || this.tr.length != this.tr.length) return;
for (var i /*:int*/ = 0; i < 16; i++) this.tr[i] = tr[i];
}

//============================================================
//    L2DMatrix44 # getScaleX()
//============================================================
L2DMatrix44.prototype.getScaleX = function() {
return this.tr[0];
}

//============================================================
//    L2DMatrix44 # getScaleY()
//============================================================
L2DMatrix44.prototype.getScaleY = function() {
return this.tr[5];
}

//============================================================
//    L2DMatrix44 # transformX()
//============================================================
L2DMatrix44.prototype.transformX = function(src /*float*/ ) {
return this.tr[0] * src + this.tr[12];
}

//============================================================
//    L2DMatrix44 # transformY()
//============================================================
L2DMatrix44.prototype.transformY = function(src /*float*/ ) {
return this.tr[5] * src + this.tr[13];
}

//============================================================
//    L2DMatrix44 # invertTransformX()
//============================================================
L2DMatrix44.prototype.invertTransformX = function(src /*float*/ ) {
return (src - this.tr[12]) / this.tr[0];
}

//============================================================
//    L2DMatrix44 # invertTransformY()
//============================================================
L2DMatrix44.prototype.invertTransformY = function(src /*float*/ ) {
return (src - this.tr[13]) / this.tr[5];
}

//============================================================
//    L2DMatrix44 # multTranslate()
//============================================================
L2DMatrix44.prototype.multTranslate = function(shiftX /*float*/ , shiftY /*float*/ ) {
var tr1 = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, shiftX, shiftY, 0, 1];
L2DMatrix44.mul(tr1, this.tr, this.tr);
}

//============================================================
//    L2DMatrix44 # translate()
//============================================================
L2DMatrix44.prototype.translate = function(x /*float*/ , y /*float*/ ) {
this.tr[12] = x;
this.tr[13] = y;
}

//============================================================
//    L2DMatrix44 # translateX()
//============================================================
L2DMatrix44.prototype.translateX = function(x /*float*/ ) {
this.tr[12] = x;
}

//============================================================
//    L2DMatrix44 # translateY()
//============================================================
L2DMatrix44.prototype.translateY = function(y /*float*/ ) {
this.tr[13] = y;
}

//============================================================
//    L2DMatrix44 # multScale()
//============================================================
L2DMatrix44.prototype.multScale = function(scaleX /*float*/ , scaleY /*float*/ ) {
var tr1 = [scaleX, 0, 0, 0, 0, scaleY, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
L2DMatrix44.mul(tr1, this.tr, this.tr);
}

//============================================================
//    L2DMatrix44 # scale()
//============================================================
L2DMatrix44.prototype.scale = function(scaleX /*float*/ , scaleY /*float*/ ) {
this.tr[0] = scaleX;
this.tr[5] = scaleY;
}
/**
 *
 *  You can modify and use this source freely
 *  only for the development of application related Live2D.
 *
 *  (c) Live2D Inc. All rights reserved.
 */

//============================================================
//============================================================
//  class L2DModelMatrix       extends     L2DMatrix44
//============================================================
//============================================================
function L2DModelMatrix(w /*float*/ , h /*float*/ ) {
    L2DMatrix44.prototype.constructor.call(this);
    this.width = w;
    this.height = h;
}

//L2DModelMatrix extends L2DMatrix44
L2DModelMatrix.prototype = new L2DMatrix44();

//============================================================
//    L2DModelMatrix # setPosition()
//============================================================
L2DModelMatrix.prototype.setPosition = function(x /*float*/ , y /*float*/ ) {
this.translate(x, y);
}

//============================================================
//    L2DModelMatrix # setCenterPosition()
//============================================================
L2DModelMatrix.prototype.setCenterPosition = function(x /*float*/ , y /*float*/ ) {
var w = this.width * this.getScaleX();
var h = this.height * this.getScaleY();
this.translate(x - w / 2, y - h / 2);
}

//============================================================
//    L2DModelMatrix # top()
//============================================================
L2DModelMatrix.prototype.top = function(y /*float*/ ) {
this.setY(y);
}

//============================================================
//    L2DModelMatrix # bottom()
//============================================================
L2DModelMatrix.prototype.bottom = function(y /*float*/ ) {
var h = this.height * this.getScaleY();
this.translateY(y - h);
}

//============================================================
//    L2DModelMatrix # left()
//============================================================
L2DModelMatrix.prototype.left = function(x /*float*/ ) {
this.setX(x);
}

//============================================================
//    L2DModelMatrix # right()
//============================================================
L2DModelMatrix.prototype.right = function(x /*float*/ ) {
var w = this.width * this.getScaleX();
this.translateX(x - w);
}

//============================================================
//    L2DModelMatrix # centerX()
//============================================================
L2DModelMatrix.prototype.centerX = function(x /*float*/ ) {
var w = this.width * this.getScaleX();
this.translateX(x - w / 2);
}

//============================================================
//    L2DModelMatrix # centerY()
//============================================================
L2DModelMatrix.prototype.centerY = function(y /*float*/ ) {
var h = this.height * this.getScaleY();
this.translateY(y - h / 2);
}

//============================================================
//    L2DModelMatrix # setX()
//============================================================
L2DModelMatrix.prototype.setX = function(x /*float*/ ) {
this.translateX(x);
}

//============================================================
//    L2DModelMatrix # setY()
//============================================================
L2DModelMatrix.prototype.setY = function(y /*float*/ ) {
this.translateY(y);
}

//============================================================
//    L2DModelMatrix # setHeight()
//============================================================
L2DModelMatrix.prototype.setHeight = function(h /*float*/ ) {
var scaleX = h / this.height;
var scaleY = -scaleX;
this.scale(scaleX, scaleY);
}

//============================================================
//    L2DModelMatrix # setWidth()
//============================================================
L2DModelMatrix.prototype.setWidth = function(w /*float*/ ) {
var scaleX = w / this.width;
var scaleY = -scaleX;
this.scale(scaleX, scaleY);
}

/**
 *
 *  You can modify and use this source freely
 *  only for the development of application related Live2D.
 *
 *  (c) Live2D Inc. All rights reserved.
 */

//============================================================
//============================================================
//  class L2DMotionManager     extends     MotionQueueManager
//============================================================
//============================================================
function L2DMotionManager() {
    MotionQueueManager.prototype.constructor.call(this);
    this.currentPriority = null;
    this.reservePriority = null;

    this.super = MotionQueueManager.prototype;
}


L2DMotionManager.prototype = new MotionQueueManager();

//============================================================
//    L2DMotionManager # getCurrentPriority()
//============================================================
L2DMotionManager.prototype.getCurrentPriority = function() {
return this.currentPriority;
}

//============================================================
//    L2DMotionManager # getReservePriority()
//============================================================
L2DMotionManager.prototype.getReservePriority = function() {
return this.reservePriority;
}

//============================================================
//    L2DMotionManager # reserveMotion()
//============================================================
L2DMotionManager.prototype.reserveMotion = function(priority /*int*/ ) {
if (this.reservePriority >= priority) {
    return false;
}
if (this.currentPriority >= priority) {
    return false;
}

this.reservePriority = priority;

return true;
}

//============================================================
//    L2DMotionManager # setReservePriority()
//============================================================
L2DMotionManager.prototype.setReservePriority = function(val /*int*/ ) {
this.reservePriority = val;
}

//============================================================
//    L2DMotionManager # updateParam()
//============================================================
L2DMotionManager.prototype.updateParam = function(model /*ALive2DModel*/ ) {
var updated = MotionQueueManager.prototype.updateParam.call(this, model);

if (this.isFinished()) {
    this.currentPriority = 0;
}

return updated;
}

//============================================================
//    L2DMotionManager # startMotionPrio()
//============================================================
L2DMotionManager.prototype.startMotionPrio = function(motion /*AMotion*/ , priority /*int*/ ) {
if (priority == this.reservePriority) {
    this.reservePriority = 0;
}
this.currentPriority = priority;
return this.startMotion(motion, false);
}

/**
 *
 *  You can modify and use this source freely
 *  only for the development of application related Live2D.
 *
 *  (c) Live2D Inc. All rights reserved.
 */

//============================================================
//============================================================
//  class L2DPhysics           
//============================================================
//============================================================
function L2DPhysics() {
    this.physicsList = new Array(); //ArrayList<PhysicsHair>
    this.startTimeMSec = UtSystem.getUserTimeMSec();
}

//============================================================
//    static L2DPhysics.load()
//============================================================
L2DPhysics.load = function(buf /*byte[]*/ ) {
var ret = new L2DPhysics(); //L2DPhysicsL2DPhysics
var pm = Live2DFramework.getPlatformManager();
var json = pm.jsonParseFromBytes(buf);
var params = json.physics_hair;
var paramNum = params.length;
for (var i = 0; i < paramNum; i++) {
    var param = params[i]; //Value
    var physics = new PhysicsHair(); //PhysicsHairPhysicsHair
    var setup = param.setup; //Value
    var length = parseFloat(setup.length);
    var resist = parseFloat(setup.regist);
    var mass = parseFloat(setup.mass);
    physics.setup(length, resist, mass);
    var srcList = param.src; //Value
    var srcNum = srcList.length;
    for (var j = 0; j < srcNum; j++) {
        var src = srcList[j]; //Value
        var id = src.id; //String
        var type = PhysicsHair.Src.SRC_TO_X;
        var typeStr = src.ptype; //String
        if (typeStr === 'x') {
            type = PhysicsHair.Src.SRC_TO_X;
        } else if (typeStr === 'y') {
            type = PhysicsHair.Src.SRC_TO_Y;
        } else if (typeStr === 'angle') {
            type = PhysicsHair.Src.SRC_TO_G_ANGLE;
        } else {
            UtDebug.error('live2d', 'Invalid parameter:PhysicsHair.Src');
        }
        var scale = parseFloat(src.scale);
        var weight = parseFloat(src.weight);
        physics.addSrcParam(type, id, scale, weight);
    }
    var targetList = param.targets; //Value
    var targetNum = targetList.length;
    for (var j = 0; j < targetNum; j++) {
        var target = targetList[j]; //Value
        var id = target.id; //String
        var type = PhysicsHair.Target.TARGET_FROM_ANGLE;
        var typeStr = target.ptype; //String
        if (typeStr === 'angle') {
            type = PhysicsHair.Target.TARGET_FROM_ANGLE;
        } else if (typeStr === 'angle_v') {
            type = PhysicsHair.Target.TARGET_FROM_ANGLE_V;
        } else {
            UtDebug.error('live2d', 'Invalid parameter:PhysicsHair.Target');
        }
        var scale = parseFloat(target.scale);
        var weight = parseFloat(target.weight);
        physics.addTargetParam(type, id, scale, weight);
    }
    ret.physicsList.push(physics);
}
return ret;
}

//============================================================
//    L2DPhysics # updateParam()
//============================================================
L2DPhysics.prototype.updateParam = function(model /*ALive2DModel*/ ) {
var timeMSec = UtSystem.getUserTimeMSec() - this.startTimeMSec;
for (var i = 0; i < this.physicsList.length; i++) {
    this.physicsList[i].update(model, timeMSec);
}
}

/**
 *
 *  You can modify and use this source freely
 *  only for the development of application related Live2D.
 *
 *  (c) Live2D Inc. All rights reserved.
 */

//============================================================
//============================================================
//  class L2DPose              
//============================================================
//============================================================
function L2DPose() {
    this.lastTime = 0;
    this.lastModel = null; //ALive2DModel
    this.partsGroups = new Array(); //ArrayList<L2DPartsParam[]>
}


//============================================================
//    static L2DPose.load()
//============================================================
L2DPose.load = function(buf /*byte[]*/ ) {
var ret = new L2DPose(); //L2DPose
var pm = Live2DFramework.getPlatformManager();
var json = pm.jsonParseFromBytes(buf);
var poseListInfo = json.parts_visible; //Value
var poseNum = poseListInfo.length;
for (var i_pose = 0; i_pose < poseNum; i_pose++) {
    var poseInfo = poseListInfo[i_pose]; //Value
    var idListInfo = poseInfo.group; //Value
    var idNum = idListInfo.length;
    var partsGroup /*L2DPartsParam*/ = new Array();
    for (var i_group = 0; i_group < idNum; i_group++) {
        var partsInfo = idListInfo[i_group]; //Value
        var parts = new L2DPartsParam(partsInfo.id); //L2DPartsParamL2DPartsParam
        partsGroup[i_group] = parts;
        if (partsInfo.link == null) continue;
        var linkListInfo = partsInfo.link; //Value
        var linkNum = linkListInfo.length;
        parts.link = new Array(); //ArrayList<L2DPartsParam>
        for (var i_link = 0; i_link < linkNum; i_link++) {
            var linkParts = new L2DPartsParam(linkListInfo[i_link]); //L2DPartsParamL2DPartsParam
            parts.link.push(linkParts);
        }
    }
    ret.partsGroups.push(partsGroup);
}

return ret;
}

//============================================================
//    L2DPose # updateParam()
//============================================================
L2DPose.prototype.updateParam = function(model /*ALive2DModel*/ ) {
if (model == null) return;

if (!(model == this.lastModel)) {
    this.initParam(model);
}
this.lastModel = model;

var curTime = UtSystem.getUserTimeMSec();
var deltaTimeSec = ((this.lastTime == 0) ? 0 : (curTime - this.lastTime) / 1000.0);
this.lastTime = curTime;
if (deltaTimeSec < 0)
    deltaTimeSec = 0;
for (var i = 0; i < this.partsGroups.length; i++) {
    this.normalizePartsOpacityGroup(model, this.partsGroups[i], deltaTimeSec);
    this.copyOpacityOtherParts(model, this.partsGroups[i]);
}
}

//============================================================
//    L2DPose # initParam()
//============================================================
L2DPose.prototype.initParam = function(model /*ALive2DModel*/ ) {
if (model == null) return;
for (var i = 0; i < this.partsGroups.length; i++) {
    var partsGroup = this.partsGroups[i]; //L2DPartsParam
    for (var j = 0; j < partsGroup.length; j++) {
        partsGroup[j].initIndex(model);
        var partsIndex = partsGroup[j].partsIndex;
        var paramIndex = partsGroup[j].paramIndex;
        if (partsIndex < 0) continue;
        var v /*:Boolean*/ = (model.getParamFloat(paramIndex) != 0);
        model.setPartsOpacity(partsIndex, (v ? 1.0 : 0.0));
        model.setParamFloat(paramIndex, (v ? 1.0 : 0.0));
        if (partsGroup[j].link == null) continue;
        for (var k = 0; k < partsGroup[j].link.length; k++) {
            partsGroup[j].link[k].initIndex(model);
        }
    }
}
}

//============================================================
//    L2DPose # normalizePartsOpacityGroup()
//============================================================
L2DPose.prototype.normalizePartsOpacityGroup = function(model /*ALive2DModel*/ , partsGroup /*L2DPartsParam[]*/ , deltaTimeSec /*float*/ ) {
var visibleParts = -1;
var visibleOpacity = 1.0;
var CLEAR_TIME_SEC = 0.5;
var phi = 0.5;
var maxBackOpacity = 0.15;
for (var i = 0; i < partsGroup.length; i++) {
    var partsIndex = partsGroup[i].partsIndex;
    var paramIndex = partsGroup[i].paramIndex;
    if (partsIndex < 0) continue;
    if (model.getParamFloat(paramIndex) != 0) {
        if (visibleParts >= 0) {
            break;
        }
        visibleParts = i;
        visibleOpacity = model.getPartsOpacity(partsIndex);
        visibleOpacity += deltaTimeSec / CLEAR_TIME_SEC;
        if (visibleOpacity > 1) {
            visibleOpacity = 1;
        }
    }
}
if (visibleParts < 0) {
    visibleParts = 0;
    visibleOpacity = 1;
}
for (var i = 0; i < partsGroup.length; i++) {
    var partsIndex = partsGroup[i].partsIndex;
    if (partsIndex < 0) continue;
    if (visibleParts == i) {
        model.setPartsOpacity(partsIndex, visibleOpacity);
    } else {
        var opacity = model.getPartsOpacity(partsIndex);
        var a1;
        if (visibleOpacity < phi) {
            a1 = visibleOpacity * (phi - 1) / phi + 1;
        } else {
            a1 = (1 - visibleOpacity) * phi / (1 - phi);
        }
        var backOp = (1 - a1) * (1 - visibleOpacity);
        if (backOp > maxBackOpacity) {
            a1 = 1 - maxBackOpacity / (1 - visibleOpacity);
        }
        if (opacity > a1) {
            opacity = a1;
        }
        model.setPartsOpacity(partsIndex, opacity);
    }
}
}

//============================================================
//    L2DPose # copyOpacityOtherParts()
//============================================================
L2DPose.prototype.copyOpacityOtherParts = function(model /*ALive2DModel*/ , partsGroup /*L2DPartsParam[]*/ ) {
for (var i_group = 0; i_group < partsGroup.length; i_group++) {
    var partsParam = partsGroup[i_group]; //L2DPartsParam
    if (partsParam.link == null) continue;
    if (partsParam.partsIndex < 0) continue;
    var opacity = model.getPartsOpacity(partsParam.partsIndex);
    for (var i_link = 0; i_link < partsParam.link.length; i_link++) {
        var linkParts = partsParam.link[i_link]; //L2DPartsParam
        if (linkParts.partsIndex < 0) continue;
        model.setPartsOpacity(linkParts.partsIndex, opacity);
    }
}
}

//============================================================
//============================================================
//  class L2DPartsParam        
//============================================================
//============================================================
function L2DPartsParam(id /*String*/ ) {
    this.paramIndex = -1;
    this.partsIndex = -1;
    this.link = null; // ArrayList<L2DPartsParam>
    this.id = id;
}

//============================================================
//    L2DPartsParam # initIndex()
//============================================================
L2DPartsParam.prototype.initIndex = function(model /*ALive2DModel*/ ) {
this.paramIndex = model.getParamIndex('VISIBLE:' + this.id);
this.partsIndex = model.getPartsDataIndex(PartsDataID.getID(this.id));
model.setParamFloat(this.paramIndex, 1);
}
/**
 *
 *  You can modify and use this source freely
 *  only for the development of application related Live2D.
 *
 *  (c) Live2D Inc. All rights reserved.
 */

//============================================================
//============================================================
//  class L2DTargetPoint       
//============================================================
//============================================================
function L2DTargetPoint() {
    this.EPSILON = 0.01; // 変化の最小値（この値以下は無視される）
    this.faceTargetX = 0;
    this.faceTargetY = 0;
    this.faceX = 0;
    this.faceY = 0;
    this.faceVX = 0;
    this.faceVY = 0;
    this.lastTimeSec = 0;
}

//============================================================
L2DTargetPoint.FRAME_RATE = 30;

//============================================================
//    L2DTargetPoint # set()
//============================================================
L2DTargetPoint.prototype.setPoint = function(x /*float*/ , y /*float*/ ) {
this.faceTargetX = x;
this.faceTargetY = y;
}

//============================================================
//    L2DTargetPoint # getX()
//============================================================
L2DTargetPoint.prototype.getX = function() {
return this.faceX;
}

//============================================================
//    L2DTargetPoint # getY()
//============================================================
L2DTargetPoint.prototype.getY = function() {
return this.faceY;
}

//============================================================
//    L2DTargetPoint # update()
//============================================================
L2DTargetPoint.prototype.update = function() {
var TIME_TO_MAX_SPEED = 0.15;
var FACE_PARAM_MAX_V = 40.0 / 7.5;
var MAX_V = FACE_PARAM_MAX_V / L2DTargetPoint.FRAME_RATE;
if (this.lastTimeSec == 0) {
    this.lastTimeSec = UtSystem.getUserTimeMSec();
    return;
}
var curTimeSec = UtSystem.getUserTimeMSec();
var deltaTimeWeight = (curTimeSec - this.lastTimeSec) * L2DTargetPoint.FRAME_RATE / 1000.0;
this.lastTimeSec = curTimeSec;
var FRAME_TO_MAX_SPEED = TIME_TO_MAX_SPEED * L2DTargetPoint.FRAME_RATE;
var MAX_A = deltaTimeWeight * MAX_V / FRAME_TO_MAX_SPEED;
var dx = (this.faceTargetX - this.faceX);
var dy = (this.faceTargetY - this.faceY);
// if(dx == 0 && dy == 0) return;
if (Math.abs(dx) <= this.EPSILON && Math.abs(dy) <= this.EPSILON) return;
var d = Math.sqrt(dx * dx + dy * dy);
var vx = MAX_V * dx / d;
var vy = MAX_V * dy / d;
var ax = vx - this.faceVX;
var ay = vy - this.faceVY;
var a = Math.sqrt(ax * ax + ay * ay);
if (a < -MAX_A || a > MAX_A) {
    ax *= MAX_A / a;
    ay *= MAX_A / a;
    a = MAX_A;
}
this.faceVX += ax;
this.faceVY += ay;
{
    var max_v = 0.5 * (Math.sqrt(MAX_A * MAX_A + 16 * MAX_A * d - 8 * MAX_A * d) - MAX_A);
    var cur_v = Math.sqrt(this.faceVX * this.faceVX + this.faceVY * this.faceVY);
    if (cur_v > max_v) {
        this.faceVX *= max_v / cur_v;
        this.faceVY *= max_v / cur_v;
    }
}
this.faceX += this.faceVX;
this.faceY += this.faceVY;
}
/**
 *
 *  You can modify and use this source freely
 *  only for the development of application related Live2D.
 *
 *  (c) Live2D Inc. All rights reserved.
 */

//============================================================
//============================================================
//  class L2DViewMatrix        extends     L2DMatrix44
//============================================================
//============================================================
function L2DViewMatrix() {
    L2DMatrix44.prototype.constructor.call(this);
    this.screenLeft = null;
    this.screenRight = null;
    this.screenTop = null;
    this.screenBottom = null;
    this.maxLeft = null;
    this.maxRight = null;
    this.maxTop = null;
    this.maxBottom = null;
    this.max = Number.MAX_VALUE;
    this.min = 0;
}

L2DViewMatrix.prototype = new L2DMatrix44(); //L2DViewMatrix extends L2DMatrix44

//============================================================
//    L2DViewMatrix # getMaxScale()
//============================================================
L2DViewMatrix.prototype.getMaxScale = function() {
return this.max;
}

//============================================================
//    L2DViewMatrix # getMinScale()
//============================================================
L2DViewMatrix.prototype.getMinScale = function() {
return this.min;
}

//============================================================
//    L2DViewMatrix # setMaxScale()
//============================================================
L2DViewMatrix.prototype.setMaxScale = function(v /*float*/ ) {
this.max = v;
}

//============================================================
//    L2DViewMatrix # setMinScale()
//============================================================
L2DViewMatrix.prototype.setMinScale = function(v /*float*/ ) {
this.min = v;
}

//============================================================
//    L2DViewMatrix # isMaxScale()
//============================================================
L2DViewMatrix.prototype.isMaxScale = function() {
return this.getScaleX() == this.max;
}

//============================================================
//    L2DViewMatrix # isMinScale()
//============================================================
L2DViewMatrix.prototype.isMinScale = function() {
return this.getScaleX() == this.min;
}

//============================================================
//    L2DViewMatrix # adjustTranslate()
//============================================================
L2DViewMatrix.prototype.adjustTranslate = function(shiftX /*float*/ , shiftY /*float*/ ) {
if (this.tr[0] * this.maxLeft + (this.tr[12] + shiftX) > this.screenLeft)
    shiftX = this.screenLeft - this.tr[0] * this.maxLeft - this.tr[12];
if (this.tr[0] * this.maxRight + (this.tr[12] + shiftX) < this.screenRight)
    shiftX = this.screenRight - this.tr[0] * this.maxRight - this.tr[12];
if (this.tr[5] * this.maxTop + (this.tr[13] + shiftY) < this.screenTop)
    shiftY = this.screenTop - this.tr[5] * this.maxTop - this.tr[13];
if (this.tr[5] * this.maxBottom + (this.tr[13] + shiftY) > this.screenBottom)
    shiftY = this.screenBottom - this.tr[5] * this.maxBottom - this.tr[13];

var tr1 = [1, 0, 0, 0,
    0, 1, 0, 0,
    0, 0, 1, 0,
    shiftX, shiftY, 0, 1];
L2DMatrix44.mul(tr1, this.tr, this.tr);
}

//============================================================
//    L2DViewMatrix # adjustScale()
//============================================================
L2DViewMatrix.prototype.adjustScale = function(cx /*float*/ , cy /*float*/ , scale /*float*/ ) {
var targetScale = scale * this.tr[0];
if (targetScale < this.min) {
    if (this.tr[0] > 0)
        scale = this.min / this.tr[0];
} else if (targetScale > this.max) {
    if (this.tr[0] > 0)
        scale = this.max / this.tr[0];
}
var tr1 = [1, 0, 0, 0,
    0, 1, 0, 0,
    0, 0, 1, 0,
    cx, cy, 0, 1];
var tr2 = [scale, 0, 0, 0,
    0, scale, 0, 0,
    0, 0, 1, 0,
    0, 0, 0, 1];
var tr3 = [1, 0, 0, 0,
    0, 1, 0, 0,
    0, 0, 1, 0,
    -cx, -cy, 0, 1];
L2DMatrix44.mul(tr3, this.tr, this.tr);
L2DMatrix44.mul(tr2, this.tr, this.tr);
L2DMatrix44.mul(tr1, this.tr, this.tr);
}

//============================================================
//    L2DViewMatrix # setScreenRect()
//============================================================
L2DViewMatrix.prototype.setScreenRect = function(left /*float*/ , right /*float*/ , bottom /*float*/ , top /*float*/ ) {
this.screenLeft = left;
this.screenRight = right;
this.screenTop = top;
this.screenBottom = bottom;
}

//============================================================
//    L2DViewMatrix # setMaxScreenRect()
//============================================================
L2DViewMatrix.prototype.setMaxScreenRect = function(left /*float*/ , right /*float*/ , bottom /*float*/ , top /*float*/ ) {
this.maxLeft = left;
this.maxRight = right;
this.maxTop = top;
this.maxBottom = bottom;
}

//============================================================
//    L2DViewMatrix # getScreenLeft()
//============================================================
L2DViewMatrix.prototype.getScreenLeft = function() {
return this.screenLeft;
}

//============================================================
//    L2DViewMatrix # getScreenRight()
//============================================================
L2DViewMatrix.prototype.getScreenRight = function() {
return this.screenRight;
}

//============================================================
//    L2DViewMatrix # getScreenBottom()
//============================================================
L2DViewMatrix.prototype.getScreenBottom = function() {
return this.screenBottom;
}

//============================================================
//    L2DViewMatrix # getScreenTop()
//============================================================
L2DViewMatrix.prototype.getScreenTop = function() {
return this.screenTop;
}

//============================================================
//    L2DViewMatrix # getMaxLeft()
//============================================================
L2DViewMatrix.prototype.getMaxLeft = function() {
return this.maxLeft;
}

//============================================================
//    L2DViewMatrix # getMaxRight()
//============================================================
L2DViewMatrix.prototype.getMaxRight = function() {
return this.maxRight;
}

//============================================================
//    L2DViewMatrix # getMaxBottom()
//============================================================
L2DViewMatrix.prototype.getMaxBottom = function() {
return this.maxBottom;
}

//============================================================
//    L2DViewMatrix # getMaxTop()
//============================================================
L2DViewMatrix.prototype.getMaxTop = function() {
return this.maxTop;
}

/**
 *
 *  You can modify and use this source freely
 *  only for the development of application related Live2D.
 *
 *  (c) Live2D Inc. All rights reserved.
 */

//============================================================
//============================================================
//  class Live2DFramework      
//============================================================
//============================================================
function Live2DFramework() {
}

//============================================================
Live2DFramework.platformManager = null;

//============================================================
//    static Live2DFramework.getPlatformManager()
//============================================================
Live2DFramework.getPlatformManager = function() {
return Live2DFramework.platformManager;
}

//============================================================
//    static Live2DFramework.setPlatformManager()
//============================================================
Live2DFramework.setPlatformManager = function(platformManager /*IPlatformManager*/ ) {
Live2DFramework.platformManager = platformManager;
}